from server_socket import ServerSocket
from socket_wrapper import SocketWrapper
from threading import Thread
from config import *
from response_protocol import *
from db import DB

class Server(object):
    """服务器核心类"""

    def __init__(self):
        #创建服务器套接字
        self.server_socket = ServerSocket()
        # 这种功能扩展更强  创建请求的id 和方法的关联字典
        # self.request_handle_function = {REQUEST_LOGIN: self.request_login_handle, REQUEST_CHAT: self.request_chat_handle}
        self.request_handle_function = {}
        self.register(REQUEST_LOGIN,self.request_login_handle)
        self.register(REQUEST_CHAT,self.request_chat_handle)

        # 创建保存当前登录用的字典
        self.clients = {}

        # 创建数据库管理对象
        self.db = DB()

    def register(self,request_id,handle_function):
        """注册消息类型和处理函数到字典里面"""
        self.request_handle_function[request_id] = handle_function

    def startup(self):
        """获取客户端链接，并提供服务"""
        while True:
            print('正在获取连接')
            # 获取客户端链接
            soc,addr = self.server_socket.accept()
            print('获取到连接')
            #使用套接字生成包装对象
            client_soc = SocketWrapper(soc)
            #收发消息 开启线程 用子线程去处理 主线程不行会报错
            # t = Thread(target=self.request_handle,args=(client_soc,))
            # t.start()
            Thread(target=lambda:self.request_handle(client_soc)).start() # 匿名函数

            #关闭客户端连接
            # soc.close()

    def request_handle(self,client_soc):
        """处理客户端请求"""
        while True:
            # 接收客户端数据
            recv_data = client_soc.recv_data()
            if not recv_data:
                # 没有接收到数据，客户端应该已经关闭
                self.remove_offline_user(client_soc)
                client_soc.close()
                break

            # 解析数据
            parse_data = self.parse_request_text(recv_data)
            # 分析数据请求类型 并根据请求类型调用相应的处理函数
            print(f'获取到解析后的内容{parse_data}')
            # if parse_data['request_id'] == REQUEST_LOGIN:
            #     self.request_login_handle()
            # elif parse_data['request_id'] == REQUEST_CHAT:
            #     self.request_chat_handle()
            handle_function = self.request_handle_function.get(parse_data['request_id'])
            if handle_function:
                handle_function(client_soc,parse_data)

            # soc.send('成功链接到服务器'.encode('utf-8'))
            # client_soc.send_data(f'服务器收到的是：{recv_data}')

    def remove_offline_user(self,client_soc):
        """客户端下线处理"""
        print(f'有用户下线')
        for username,info in self.clients.items(): # 删除多个元素 遍历里面不要删除
            if info['sock'] == client_soc:
                print(self.clients)
                del self.clients[username]
                print(self.clients)
                break

    def parse_request_text(self, text):
        """
        解析客户端发送过来的数据
        登录信息： 0001|username|password
        聊天信息：0002|username|message
        """
        print(f'客户端发送过来的数据{text}')
        request_list = text.split(DELIMITER)
        #安装类型解析数据
        request_data = {'request_id': request_list[0]}
        if request_data['request_id'] == REQUEST_LOGIN:
            # 用户请求登录
            request_data['username'] = request_list[1]
            request_data['password'] = request_list[2]
        elif request_data['request_id'] == REQUEST_CHAT:
            # 发送来聊天信息
            request_data['username'] = request_list[1]
            request_data['message'] = request_list[2]
        return request_data

    def request_login_handle(self,client_soc,request_data):
        print('收到登录请求')
        # 获取到账号密码
        username = request_data['username']
        password = request_data['password']
        # 检查是否能够登录
        ret,nickname,username = self.check_login(username,password)
        # 登录成功 则需要保存当前用户
        if ret == '1':
            self.clients[username] = {'sock':client_soc,'nickname':nickname}
        # 拼接返回给客户端的消息
        response_text = ResponseProtocol.response_login_result(ret,nickname, username)
        # 并且把消息发送给客户端
        client_soc.send_data(response_text)

    def request_chat_handle(self,client_soc,request_data):
        print(f'收到聊天请求:{request_data}')
        # 获取消息内容
        username = request_data['username']
        message = request_data['message']
        nickname = self.clients[username]['nickname']
        # 拼接消息内容 发送给用户
        msg = ResponseProtocol.response_chat(nickname,message)
        # 转发
        for u_name,info in self.clients.items():
            if username == u_name: # 当前账户和发送消息账户相同，不需要再发送数据
                continue
            info['sock'].send_data(msg)

    def check_login(self, username, password):
        """
        检查用户是否成功，并返回检查结果 0 失败 ；1 成功
        :param username: 用户名
        :param password: 密码
        :return:
        """
        # 从数据库查询用户信息
        sql = "select * from users where user_name = '%s'" % username
        result = self.db.get_one(sql)
        # 没有查询结果说明用户不存在 登录失败
        if not result:
            return '0','',username
        # 如果密码不匹配 则数码密码错误 登录失败
        if password != result['user_password']:
            return '0','',username
        # 否则登录成功
        return '1',result['user_nickname'],username


if __name__ == '__main__':
    server = Server()
    server.startup()